﻿using System;
using System.Collections.ObjectModel;
using System.Linq;
using Airborne.ScrumPoker.Model.Cards;
using Airborne.ScrumPoker.Model.TeamFoundation;
using Airborne.ScrumPoker.Module.Communication;
using Airborne.ScrumPoker.Module.Events;
using Airborne.ScrumPoker.Module.ProductOwner.Model;
using Airborne.ScrumPoker.Module.ProductOwner.Views;
using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Composite.Regions;
using Microsoft.Practices.Composite.Wpf.Events;
using Microsoft.Practices.Unity;

namespace Airborne.ScrumPoker.Module.ProductOwner.Controller
{
    public class ProjectOwnerController : IProjectOwnerController, IDisposable
    {

        #region Constructor
        public ProjectOwnerController(IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer container)
        {
            RegionManager = regionManager;
            EventAggregator = eventAggregator;
            Container = container;
        }
        #endregion

        #region Properties
        private IRegionManager RegionManager { get; set; }
        private IEventAggregator EventAggregator { get; set; }
        private IUnityContainer Container { get; set; }
        private IWorkItemDetailsView WorkItemDetailsView { get; set; }
        private ITimerDetailView TimerDetailView { get; set; }
        private IPlayerDetailView VotingDetailView { get; set; }
        private ObservableCollection<Player> Players = new ObservableCollection<Player>();
        #endregion


        public void Run()
        {
            ShowViews();
            SubscribeToEvents();
        }

        private void SubscribeToEvents()
        {
            EventAggregator.GetEvent<GenericEvent<ITeamWorkItem>>().Subscribe(WorkItemSelected, ThreadOption.UIThread, true, p => p.Topic == EventTopics.WorkItemSelected && !TimerDetailView.Timer.TimerStarted);

            EventAggregator.GetEvent<GenericEvent<string>>().Subscribe(ClientSubscribed, ThreadOption.UIThread, true, p => p.Topic == EventTopics.ClientSubscribed);
            EventAggregator.GetEvent<GenericEvent<string>>().Subscribe(ClientUnsubscribed, ThreadOption.UIThread, true, p => p.Topic == EventTopics.ClientUnsubscribed);
            EventAggregator.GetEvent<ClientVotedEvent>().Subscribe(ClientVoteReceived, ThreadOption.BackgroundThread, true);

            TimerDetailView.StartTimer += TimerStarted;
            TimerDetailView.StopTimer += TimerStopped;
            TimerDetailView.ResetVote += VoteReset;
            TimerDetailView.EndGame += EndGame;

            WorkItemDetailsView.SaveWorkItem += WorkItemDetailsViewSaveWorkItem;
            WorkItemDetailsView.NextWorkItem += WorkItemDetailsViewNextWorkItem;
            WorkItemDetailsView.PreviousWorkItem += WorkItemDetailsViewPreviousWorkItem;

        }

        private void EndGame(object sender, EventArgs e)
        {
            foreach (var player in Players)
            {
                player.VoteShown = true;
            }
        }

        private void ShowViews()
        {
            WorkItemDetailsView = Container.Resolve<IWorkItemDetailsView>();
            RegionManager.Regions[RegionNames.WorkItemRegion].AddAndActivate(WorkItemDetailsView);

            TimerDetailView = Container.Resolve<ITimerDetailView>();
            TimerDetailView.Timer = new CountdownTimer();
            RegionManager.Regions[RegionNames.ControlRegion].AddAndActivate(TimerDetailView);

            VotingDetailView = Container.Resolve<IPlayerDetailView>();
            VotingDetailView.PlayerList = Players;

            RegionManager.Regions[RegionNames.VotingRegion].AddAndActivate(VotingDetailView);
          
        }


        private void WorkItemSelected(EventParameters<ITeamWorkItem> workItemParameters)
        {
            WorkItemDetailsView.WorkItem = workItemParameters.Value;
        }

        private void ClientSubscribed(EventParameters<string> parameters)
        {
            if (!TimerDetailView.Timer.TimerStarted)
            {
                string clientName = parameters.Value;
                if (!clientName.IsNullOrEmpty())
                {
                    var clients = from c in Players
                                  where string.Compare(c.ClientName, clientName, StringComparison.OrdinalIgnoreCase) == 0
                                  select c;
                    if (clients.Count() <= 0)
                    {
                        Players.Add(new Player() { ClientName = clientName });
                    }
                }
            }
        }

        private void ClientUnsubscribed(EventParameters<string> parameters)
        {
            string clientName = parameters.Value;
            if (!clientName.IsNullOrEmpty())
            {
                var clients = from c in Players
                              where string.Compare(c.ClientName, clientName, StringComparison.OrdinalIgnoreCase) == 0
                              select c;
                if (clients.Count() > 0)
                {
                    Players.Remove(clients.First());
                }
            }
        }

        private void ClientVoteReceived(Client vote)
        {

            if (vote.IsNotNull() && !vote.ClientName.IsNullOrEmpty())
            {
                var clients = from c in Players
                              where string.Compare(c.ClientName, vote.ClientName, StringComparison.OrdinalIgnoreCase) == 0
                              select c;
                if (clients.Count() > 0)
                {
                    if (vote.Vote.HasValue)
                    {
                        clients.First().Reset();  
                        clients.First().Vote = CardFactory.GetCard(vote.Vote.Value);
                    }
                }
            }
        }

        private void VoteReset(object sender, EventArgs e)
        {

            foreach (var item in Players)
            {
                item.Reset();
            }
            TimerDetailView.Timer.Stop();
            EventAggregator.GetEvent<GenericEvent<string>>().Publish(new EventParameters<string>(EventTopics.ResetVote, string.Empty));

        }

        private void TimerStopped(object sender, EventArgs e)
        {
            TimerDetailView.Timer.Stop();
            EventAggregator.GetEvent<GenericEvent<string>>().Publish(new EventParameters<string>(EventTopics.StopTimer, string.Empty));
        }

        private void TimerStarted(object sender, GenericEventArgs<int> e)
        {
            TimerDetailView.Timer.Start(e.Data);
            EventAggregator.GetEvent<GenericEvent<int>>().Publish(new EventParameters<int>(EventTopics.StartTimer, e.Data));
        }

        private void WorkItemDetailsViewSaveWorkItem(object sender, EventArgs e)
        {
            WorkItemDetailsView.WorkItem.Save();
        }

        
        private void WorkItemDetailsViewNextWorkItem(object sender, EventArgs e)
        {
            EventAggregator.GetEvent<GenericEvent<int>>().Publish(new EventParameters<int>(EventTopics.NextWorkItemRequested, 1));
        }
        
        private void WorkItemDetailsViewPreviousWorkItem(object sender, EventArgs e)
        {
            EventAggregator.GetEvent<GenericEvent<int>>().Publish(new EventParameters<int>(EventTopics.NextWorkItemRequested, -1));
        }



        #region IDisposable Members

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {

            }
        }
        #endregion

    }
}
